/*
 * Created by Christopher King
 * Copyright (C) 2007 Christopher King, All Rights Reserved.
 */

package us.cirion.adventure.engine;

/**
 * A Verb is a command given by the player to interact with the game. Verbs can
 * include actions taken in the game world, such as eating or fighting. They can
 * also include interactions with the game system, such as saving or loading a
 * game.
 * 
 * @author Chris
 */
public class Verb extends Word
{

	/**
	 * Indicates that this Verb requires an object taken from the player's
	 * inventory. For example, most games will require that a player possess an
	 * item before they can give it away or drop it.
	 */
	public static final int INVENTORY_MANDATORY = 0;
	/**
	 * Indicates that the player may supply an object either from their
	 * inventory or from outside it. For example, a player can usually look at
	 * any item they hold as well as items they do not possess.
	 */
	public static final int INVENTORY_OPTIONAL = 1;
	/**
	 * Indicates that this Verb requires an object not present in the player's
	 * inventory. For example, a player usually cannot pick up an item they
	 * already have.
	 */
	public static final int INVENTORY_DENIED = 2;

	/**
	 * Indicates that the player must supply a noun in order to form a complete
	 * action. For example, if a player wishes to "Take", they must indicate
	 * which noun they wish to obtain.
	 */
	public static final int NOUN_MANDATORY = 0;
	/**
	 * Indicates that the player may provide a noun, but that this Verb can form
	 * a complete action without one. For example, a player may "Use Soda", but
	 * they may also have the option to "Use Soda with Pop Rocks".
	 */
	public static final int NOUN_OPTIONAL = 1;
	/**
	 * Indicates that the Verb forms a complete action, and no noun is accepted.
	 * Commands such as "Help" and "Inventory" may fall into this category.
	 */
	public static final int NOUN_DENIED = 2;

	private int takesObject = NOUN_DENIED;
	private int takesTarget = NOUN_DENIED;
	private int objectInventoryAccess = INVENTORY_DENIED;
	private int targetInventoryAccess = INVENTORY_DENIED;

	private String displayText = null;

	private int verbOrder = 0;
	private static int verbCount = 0;

	/**
	 * Construct a new instance of a Verb.
	 */
	public Verb()
	{
		// This is kind of voodoo, but it allows us to easily and automatically
		// apply a unique ID to each verb that is read in from XML. This ID can
		// later be used to reconstruct the order in which verbs were added, so
		// that the UI can display them in a resonable order rather than however
		// they randomly come back from Hashtable.
		verbOrder = verbCount;
		++verbCount;
	}

	/**
	 * Sets the human-readable text for this Verb.
	 * 
	 * @param displayText The displayable text for this Verb.
	 */
	public void setDisplayText(String displayText)
	{
		this.displayText = displayText;
	}

	/**
	 * Retrieves the human-readable text for this Verb.
	 * 
	 * @return The displayable text for this Verb.
	 */
	public String getDisplayText()
	{
		if (displayText != null)
		{
			return displayText;
		} else
		{
			return super.getDisplayText();
		}
	}

	/**
	 * Indicates this verb's rules for taking an object. The "Object" indicates
	 * the direct target of the verb.
	 * 
	 * @return {@link NOUN_MANDATORY}, {@link NOUN_OPTIONAL}, or
	 *         {@link NOUN_DENIED}.
	 */
	public int takesObject()
	{
		return takesObject;
	}

	/**
	 * Assigns this verb's rules for taking an object. The provided rule
	 * determines whether the player can or must supply a noun after ordering
	 * the verb.
	 * 
	 * @param takesObject One of {@link NOUN_MANDATORY}, {@link NOUN_OPTIONAL},
	 *            or {@link NOUN_DENIED}, depending on the desired behavior.
	 */
	public void setTakesObject(int takesObject)
	{
		this.takesObject = takesObject;
	}

	/**
	 * Retrieves this verb's rules for permitted objects. If the verb is allowed
	 * to take an object, this method will indicate what type of object is
	 * permitted: an object from within the inventory, an object from outside
	 * the inventory, or either.
	 * 
	 * @return {@link INVENTORY_MANDATORY}, {@link INVENTORY_OPTIONAL}, or
	 *         {@link INVENTORY_DENIED}.
	 */
	public int getObjectInventoryAccess()
	{
		return objectInventoryAccess;
	}

	/**
	 * Assign this verb's rules for permitted objects. Use this to indicate what
	 * types of nouns may be used with this verb.
	 * 
	 * @param inventoryAccess One of {@link INVENTORY_MANDATORY},
	 *            {@link INVENTORY_OPTIONAL}, or {@link INVENTORY_DENIED}.
	 */
	public void setObjectInventoryAccess(int inventoryAccess)
	{
		this.objectInventoryAccess = inventoryAccess;
	}

	/**
	 * Indicates this verb's rules for taking a target. The "Target" indicates
	 * the indirect object for the verb.
	 * 
	 * @return {@link NOUN_MANDATORY}, {@link NOUN_OPTIONAL}, or
	 *         {@link NOUN_DENIED}.
	 */
	public int takesTarget()
	{
		return takesTarget;
	}

	/**
	 * Assigns this verb's rules for taking an object. The provided rule
	 * determines whether the player can or must supply a noun after ordering
	 * the verb.
	 * 
	 * @param takesTarget One of {@link NOUN_MANDATORY}, {@link NOUN_OPTIONAL},
	 *            or {@link NOUN_DENIED}, depending on the desired behavior.
	 */
	public void setTakesTarget(int takesTarget)
	{
		this.takesTarget = takesTarget;
	}

	/**
	 * Retrieves this verb's rules for permitted targets. If the verb is allowed
	 * to take an target, this method will indicate what type of target is
	 * permitted: an object from within the inventory, an object from outside
	 * the inventory, or either.
	 * 
	 * @return {@link INVENTORY_MANDATORY}, {@link INVENTORY_OPTIONAL}, or
	 *         {@link INVENTORY_DENIED}.
	 */
	public int getTargetInventoryAccess()
	{
		return targetInventoryAccess;
	}

	/**
	 * Assign this verb's rules for permitted targets. Use this to indicate what
	 * types of targets may be used with this verb.
	 * 
	 * @param targetInventoryAccess One of {@link INVENTORY_MANDATORY},
	 *            {@link INVENTORY_OPTIONAL}, or {@link INVENTORY_DENIED}.
	 */
	public void setTargetInventoryAccess(int targetInventoryAccess)
	{
		this.targetInventoryAccess = targetInventoryAccess;
	}

	/**
	 * Returns the unique order of this Verb. This indicates the order in which
	 * the verb was created, which may be used to control the order in which
	 * verbs should display.
	 * 
	 * @return The ordinal number for this Verb.
	 */
	public int getVerbOrder()
	{
		return verbOrder;
	}

	/**
	 * Resets the verb order. This should be invoked if the game is ever
	 * restarted or otherwise reset, to ensure that new verbs are properly
	 * indexed from 0.
	 */
	public static void resetVerbOrder()
	{
		// This should only be called when restarting the game.
		Verb.verbCount = 0;
	}

}
